package com.yami.shop.app.controller;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.yami.shop.app.config.AppConfig;
import com.yami.shop.app.utils.HttpResult;
import com.yami.shop.bean.cashregisterapp.AppRefundGoods;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.param.OrderParam;
import com.yami.shop.bean.pay.RefundGoodsDto;
import com.yami.shop.security.util.SecurityUtils;
import com.yami.shop.service.*;
import lombok.Data;
import net.sf.jsqlparser.expression.LongValue;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.ConnectionUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import com.yami.shop.bean.pay.Orderparm;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import com.yami.shop.bean.cashregisterapp.AppTransactionRefund;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import com.yami.shop.bean.pay.RefundGoodsDto;

@Controller
@RequestMapping("/app/payOrder")
@Component
@PropertySource("classpath:application.yml")
@ConfigurationProperties(prefix = "app")
public class AppPayOrderController {

    @Autowired
    private OrderService orderService;
    @Autowired
    private AppTransactionRefundService appTransactionRefundService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private AppRefundGoodsService appRefundGoodsService;
    @Autowired
    private UserService userService;
    @Autowired
    private ShopDetailService shopDetailService;


    @Value("${appId}")
    private String appId;

    @Value("${appKey}")
    private  String appKey;

    @Value("${merchantCode}")
    private String merchantCode; //商户号

    @Value("${terminalCode}")
    private String terminalCode; //终端号

    @Value("${queryUrl}")
    private String queryUrl;//交易状态查询

    @Value("${voidPayment}")
    private String voidPayment;//支付撤销

    @Value("${refund}")
    private String refund; //交易退款

    @Value("${refundQuery}")
    private String refundQuery;//交易退款查询


    private static String authorization;



   /**
    * 交易状态查询
    * */
    @PostMapping("/queryOrderState")
    @ResponseBody
    public HttpResult query(String merchantOrderId,String originalOrderId) throws Exception{
        /* post参数,格式:JSON */
        JSONObject body = new JSONObject();
        body.put("merchantCode", merchantCode);   // 商户号
        body.put("terminalCode", terminalCode);   // 终端号
        //商户订单号与银商订单号至少存在一个
        body.put("merchantOrderId", merchantOrderId);  // 商户订单号,这里得获取原交易的商户订单号
        body.put("originalOrderId", originalOrderId);    // 银商订单号,必须与原支付交易返回的订单号一致
        //String url = "http://58.247.0.18:29015/v2/poslink/transaction/query";
        String send = send(queryUrl, body.toString());
        System.out.println("交易状态查询接口返回结果   "+send);
        JSONObject resultObject = new JSONObject(send);
        HashMap resultMap = new HashMap();
        String errCode = resultObject.getString("errCode");
        if(errCode.equals("00")){
            //查询成功
            resultMap.put("queryResCode",resultObject.getString("queryResCode"));
            resultMap.put("queryResDesc",resultObject.getString("queryResDesc"));
            resultMap.put("originalPayCode",resultObject.getString("originalPayCode"));
            resultMap.put("originalBatchNo",resultObject.getString("originalBatchNo"));
            //queryResCode 0:成功，1：超时，2：已撤销，3：已退货，4：已冲正，5：失败 ,FF交易状态未知
            return HttpResult.success(resultMap);
        }else{
            //查询失败
            //String errInfo = resultObject.getString("errInfo");
            String message="";
            switch (errCode){
                case "1000":
                    message="认证失败";
                    break;
                case "1001":
                    message="授权失败";
                    break;
                case "9001":
                    message="参数校验失败";
                    break;
                case "9999":
                    message="系统错误";
                    break;
                case "03":
                    message="无效商户";
                    break;
                case "13":
                    message="无效金额";
                    break;
                case "22":
                    message="原始交易不存在";
                    break;
                case "25":
                    message="找不到原始交易";
                    break;
                case "30":
                    message="报文格式错误";
                    break;
                case "57":
                    message="不允许此交易";
                    break;
                case "61":
                    message="超出金额限制";
                    break;
                case "64":
                    message="原始金额错误";
                    break;
                case "92":
                    message="发卡方线路异常";
                    break;
                case "94":
                    message="重复交易";
                    break;
                case "96":
                    message="交换中心异常";
                    break;
                case "97":
                    message="终端号未登记";
                    break;
                case "A7":
                    message="安全处理失败";
                    break;
                case "G1":
                    message = resultObject.getString("errInfo");
                    break;
                default:
                    message = send;
            }
            return HttpResult.failure(message);
        }
    }

    /**
     * 交易撤销
     * */
    @PostMapping("/backOut")
    @ResponseBody
    public HttpResult backOut(String orderNumber,String originalOrderId) throws Exception{
        Order order = orderService.getOrderByOrderNumber(orderNumber);
        if(order == null){
            return HttpResult.failure("订单查询失败");
        }
        RefundGoodsDto refundGoodsDto = orderService.appOrderBackOut(orderNumber,merchantCode,terminalCode,
                originalOrderId,voidPayment,appId,appKey,SecurityUtils.getSysUser().getUserId());
        return HttpResult.success(refundGoodsDto);
    }

    /**
     * 交易退款接口
     * */
    @PostMapping("/refund")
    @ResponseBody
    public HttpResult refund(@RequestBody Orderparm orderParams)throws Exception{
        ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(SecurityUtils.getSysUser().getShopId());
        boolean isVip=false;
        if(StringUtils.isNotEmpty(orderParams.getPhoneNumber())){
            User user = userService.selectUserByPhoneOne(orderParams.getPhoneNumber());
            if(user!=null){
                isVip=true;
            }
        }
        List<Product> productList = orderParams.getProductList();
        if(CollectionUtils.isEmpty(productList)){
            return HttpResult.failure("没有需要退回的商品");
        }
        //退还商品总数量
        int productCount = 0;
        Order order = orderService.getOrderByOrderNumber(orderParams.getOrderNumber());
        if(order == null){
            return HttpResult.failure("订单不存在");
        }
        for(Product product : productList){
            productCount = product.getCount()+productCount;
        }
        if(productCount>order.getProductNums()){
            return HttpResult.failure("退回商品数量超过购买数量");
        }
        for (Product product : productList) {
            OrderItem orderItem = orderItemService.getOrderItemByParam(orderParams.getOrderNumber(), product.getProdId().toString());
            if (orderItem == null) {
                return  HttpResult.failure("订单不包含此商品项");
            }
            if (product.getCount() > orderItem.getProdCount()) {
                return  HttpResult.failure("退货数量大于购买数量");
            }
        }
        RefundGoodsDto dto = appRefundGoodsService.refund(orderParams,SecurityUtils.getSysUser().getUserId(),shopDetail.getMerchantCode(),
                shopDetail.getTerminalCode(),refund,SecurityUtils.getSysUser().getShopId(),appId,appKey,isVip);
        return HttpResult.success(dto);
    }


    /**
     * 交易退款
     * */
   /* @PostMapping("/refund")
    @ResponseBody
    public  HttpResult refund(String orderNumber, int amount, String originalOrderId, @RequestBody Orderparm orderParams) throws Exception{
        List<AppProductPool> productList = orderParams.getProductList();

        Order orderParam = new Order();
        orderParam.setOrderNumber(orderNumber);
        orderParam.setOriginalOrderId(originalOrderId);//银商订单号
        Order order = orderService.getOrderByOrderNumber(orderNumber);
        Long refundRequestId = 0l;
        String payCode=null;
        if(order != null){
            //订单数据异常
            return HttpResult.failure("订单数据异常");
        }else{
           AppTransactionRefund appTransactionRefund = new AppTransactionRefund();
            appTransactionRefund.setMerchantOrderId(Long.valueOf(orderNumber));
            appTransactionRefund.setOriginalOrderId(originalOrderId);
           List<AppTransactionRefund> appTransactionRefundList = appTransactionRefundService.getList(appTransactionRefund);
           if(CollectionUtils.isNotEmpty(appTransactionRefundList)){
               refundRequestId = Long.valueOf(DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.randomNumeric(4));
           }else{
               refundRequestId = appTransactionRefundList.get(0).getRefundRequestId();
               payCode = appTransactionRefundList.get(0).getPayCode();
           }
        }
        *//* post参数,格式:JSON *//*
        JSONObject body = new JSONObject();
        body.put("merchantCode", merchantCode);   // 商户号
        body.put("terminalCode", terminalCode);   // 终端号
//      body.put("merchantOrderId", "201905211550526234902343");  // 商户订单号,这里得获取原交易的商户订单号
        body.put("originalOrderId", originalOrderId);    // 银商订单号,必须与原支付交易返回的订单号一致
        body.put("refundRequestId", refundRequestId); // 退款请求标识,标识一次退款请求,跟退款订单号一个效果
        body.put("transactionAmount", 1);   // 退货金额,代表本次退货的金额,小于或等于原支付金额
//      body.put("limitCrossDevice", true); // 是否限制跨终端,true不可以跨终端,false:可以跨终端
//      body.put("srcReserved", "商户冗余信息");  // 商户冗余信息
//      body.put("storeId", "001"); // 门店号
//      body.put("operatorId", "001");  // 操作员编号
//      body.put("bizIdentifier", "业务标识");// 业务标识,一般不上送
        String send = send(refund, body.toString());
        JSONObject json = new JSONObject(send);
        String errCode = json.getString("errCode");
        if(errCode.equals("00")){//退款成功
            AppTransactionRefund appTransactionRefund = new AppTransactionRefund();
            appTransactionRefund.setMerchantCode(merchantCode);
            appTransactionRefund.setTerminalCode(terminalCode);
            appTransactionRefund.setMerchantOrderId(Long.valueOf(orderNumber));
            appTransactionRefund.setOriginalOrderId(originalOrderId);
            appTransactionRefund.setRefundRequestId(refundRequestId);
            appTransactionRefund.setCreateTime(new Date());
            appTransactionRefund.setShopId(SecurityUtils.getSysUser().getShopId());
            appTransactionRefund.setUserId(SecurityUtils.getSysUser().getUserId());
            appTransactionRefund.setPayCode(payCode);
            appTransactionRefund.setAmount(amount);
            appTransactionRefundService.save(appTransactionRefund);
            //修改订单信息
            return HttpResult.success(appTransactionRefund);
        }else{//退款失败
            return HttpResult.failure(json.getString("errInfo"));
        }
    }*/

    /**
     * 交易退款查询
     *
     * 测试环境：http://58.247.0.18:29015/v2/poslink/transaction/query-refund
     * 生产环境：https://api-mop.chinaums.com/v2/poslink/transaction/query-refund
     */
    @PostMapping("/refundQuery")
    @ResponseBody
    public  HttpResult refundQuery(String orderNumber,String originalOrderId,String refundRequestId) throws Exception {
        ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(SecurityUtils.getSysUser().getShopId());
        /* post参数,格式:JSON */
        JSONObject body = new JSONObject();
        body.put("merchantCode", shopDetail.getMerchantCode());   // 商户号
        body.put("terminalCode", shopDetail.getTerminalCode());   // 终端号
        body.put("merchantOrderId", orderNumber);  // 商户订单号,这里得获取原交易的商户订单号
        body.put("originalOrderId", originalOrderId);    // 银商订单号,必须与原支付交易返回的订单号一致
        body.put("refundRequestId", refundRequestId); // 退款请求标识,标识一次退款请求,这个得跟原退款交易中的一致
        String send = send(refundQuery, body.toString());
        JSONObject resultObject = new JSONObject(send);
        System.out.println("返回结果:\n"+send);
        String errCode = resultObject.getString("errCode");
        HashMap resultMap = new HashMap();
        if(errCode.equals("00")){
            resultMap.put("payCode",resultObject.getString("payCode"));
            resultMap.put("dealDate",resultObject.getString("dealDate"));//所查询交易日期
            resultMap.put("dealTime",resultObject.getString("dealTime"));//所查询交易时间
            resultMap.put("originalAmount",resultObject.getString("originalAmount"));//原终端上送金额
            resultMap.put("dealType",resultObject.getString("dealType"));//交易类型
            resultMap.put("dealSystemTraceNum",resultObject.getString("dealSystemTraceNum"));//所查询交易流水
            resultMap.put("dealRetrievalRefNum",resultObject.getString("dealRetrievalRefNum"));//所查询交易系统参考号
            resultMap.put("batchNo",resultObject.getString("batchNo"));//批次号
            resultMap.put("originalTransactionDate",resultObject.getString("originalTransactionDate"));//原交易日期
            resultMap.put("origialRetrievalRefNum",resultObject.getString("origialRetrievalRefNum"));//原交易系统参数
            resultMap.put("originalSettlementDate",resultObject.getString("originalSettlementDate"));//原始交易清算日期
            resultMap.put("refundInvoiceAmount",resultObject.getString("refundInvoiceAmount"));//实际退款金额
            //resultMap.put("transactionAmount",resultObject.getString("transactionAmount"));//交易金额
            return HttpResult.success(resultMap);
        }else{
            return HttpResult.failure(resultObject.getString("errInfo"));
        }
    }

    /**
     * 发送请求
     * */
    public String send(String url,String entity) throws Exception{
        authorization = getOpenBodySig(appId,appKey,entity);
        System.out.println("authorization"+authorization);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Authorization", authorization);
        StringEntity se = new StringEntity(entity, "UTF-8");
        se.setContentType("application/json");
        System.out.println("se"+se);
        httpPost.setEntity(se);
        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity1 = response.getEntity();
        String resStr = null;
        if (entity1 != null) {
            resStr = EntityUtils.toString(entity1, "UTF-8");
        }
        httpClient.close();
        response.close();
        return resStr;
    }

    /**
     * open-body-sig方式获取到Authorization 的值
     *
     * @param appId  f0ec96ad2c3848b5b810e7aadf369e2f
     * @param appKey 775481e2556e4564985f5439a5e6a277
     * @param body
     * @return
     * @throws Exception
     */
    public static String getOpenBodySig(String appId, String appKey, String body) throws Exception {
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());   // eg:20190227113148
        String nonce = UUID.randomUUID().toString().replace("-", ""); // eg:be46cd581c9f46ecbd71b9858311ea12
        byte[] data = body.getBytes("UTF-8");
        System.out.println("data:\n" + body);
        InputStream is = new ByteArrayInputStream(data);
        String bodyDigest = testSHA256(is); // eg:d60bc3aedeb853e2a11c0c096baaf19954dd9b752e48dea8e919e5fb29a42a8d
        System.out.println("bodyDigest:\n" + bodyDigest);
        String str1_C = appId + timestamp + nonce + bodyDigest; // eg:f0ec96ad2c3848b5b810e7aadf369e2f + 20190227113148 + be46cd581c9f46ecbd71b9858311ea12 + d60bc3aedeb853e2a11c0c096baaf19954dd9b752e48dea8e919e5fb29a42a8d
        System.out.println("str1_C:" + str1_C);
        byte[] localSignature = hmacSHA256(str1_C.getBytes(), appKey.getBytes());
        String localSignatureStr = Base64.encodeBase64String(localSignature);   // Signature
        System.out.println("Authorization:\n" + "OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\"\n");
        return ("OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\"");
    }
    /**
     * 进行加密
     *
     * @param is
     * @return 加密后的结果
     */
    private static String testSHA256(InputStream is) {
        try {
            return DigestUtils.sha256Hex(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param data
     * @param key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public static byte[] hmacSHA256(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {
        String algorithm = "HmacSHA256";
        Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(key, algorithm));
        return mac.doFinal(data);
    }

    private String CheckErrCode(String errCode){
        String result="";
        switch (errCode){
            case "1000":
                result = "1";
                break;
        }
        return result;
    }



}
